#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
 
#include <linux/device.h>
#include <linux/kfifo.h>
#define MAX_SIZE          256  //fifo空间大小

#define DEVICE_NUM        4    //支持4个设备

static DEFINE_KFIFO(vsfifo0, char, MAX_SIZE);
static DEFINE_KFIFO(vsfifo1, char, MAX_SIZE);
static DEFINE_KFIFO(vsfifo2, char, MAX_SIZE);
static DEFINE_KFIFO(vsfifo3, char, MAX_SIZE);

static struct class *class;
static struct device *classdev;
static dev_t devno;
static int major;  
static struct cdev cdev;



static int virtdev_open(struct inode *inode, struct file *filp)
{
	//直接获得次设备号
	switch(MINOR(inode->i_rdev)){
	case 0:
		filp->private_data = &vsfifo0;
		break;
	case 1:
		filp->private_data = &vsfifo1;
		break;
	case 2:
		filp->private_data = &vsfifo2;
		break;
	case 3:
		filp->private_data = &vsfifo3;
		break;
	}

	return 0;
}
 
 
static int virtdev_release(struct inode *inode, struct file *filp)
{
	return 0;
}
 
 
static ssize_t virtdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
	unsigned int copied = 0;
	int ret;
	struct kfifo *vsfifo = filp->private_data;
	ret = kfifo_to_user(vsfifo, buf, size, &copied);
	return ret ? ret : copied;


	printk("<xyd> call %s()\n",__func__);
	
	return 0;
}
 
 
static ssize_t virtdev_write(struct file *filp, const char __user *buf, size_t size,
					loff_t *ppos)
{
	unsigned int copied = 0;
	int ret;
	struct kfifo *vsfifo = filp->private_data;
	ret = kfifo_from_user(vsfifo, buf, size, &copied);
	printk("<xyd> call %s()\n",__func__);
	
	return copied;
}
 
static const struct file_operations virtdev_fops =
{
	.owner  =  THIS_MODULE,
	.read   =  virtdev_read,
	.write  =  virtdev_write,
	.open   =  virtdev_open,
	.release = virtdev_release,
};
 
 
static int virtdev_setup_device(int index)
{
	int ret;
	int devno = MKDEV(major, index);
	//创建设备文件	
	classdev = device_create(class, NULL, devno, NULL, "virtdev%d", index);
	if (IS_ERR(classdev)) {
		ret = PTR_ERR(classdev);
		printk(KERN_ERR "device create error %d\n", ret);
		return ret;
		
	}
 
	return 0;
}
 
 
static int __init virtdev_init(void)
{
	int ret;
	int i;

	//申请一个主设备号支持四个设备 次设备号从0,1,2,3
	ret = alloc_chrdev_region(&devno, 0, DEVICE_NUM, "virtdev");
	if (ret < 0){
		ret = -EBUSY;
		return ret;
	}
		
	major = MAJOR(devno);
	
	
	class = class_create(NULL, "virtdev");
	if (IS_ERR(class)) {
		ret = PTR_ERR(class);
		printk(KERN_ERR "class_create error %d\n", ret);
		goto err_class_create;
	}

	
	for (i = 0; i < DEVICE_NUM; i++) {
		//创建四个设备对应的四个设备节点
		ret = virtdev_setup_device(i);
		if(ret) {
			printk("virtdev_setup_cdev errro\n");
			goto err_virtdev_setup_cdev;
		}
	}

	//cdev初始化注册
	cdev_init(&cdev, &virtdev_fops);
	cdev.owner = THIS_MODULE;
	ret = cdev_add(&cdev, devno, DEVICE_NUM); //1个cdev可以支持4个设备
	if (ret){
		printk(KERN_NOTICE "Error  adding virtdev");
		return ret;
	}

	printk("<xyd> call %s()\n",__func__);
	return 0;

#if 1	
err_virtdev_setup_cdev:
	while(--i){
		devno = MKDEV(major, i);
		device_destroy(class, devno);		
		
	}
	class_destroy(class);
#endif
err_class_create:
	unregister_chrdev_region(devno, DEVICE_NUM);	

	return ret;
}
static void __exit virtdev_exit(void)
{
	int i;
	int devno;
	
	for (i = 0; i < DEVICE_NUM; i++) {
		devno = MKDEV(major, i);
		device_destroy(class, devno);
		
	}
	
	class_destroy(class);
	
	unregister_chrdev_region(MKDEV(major, 0), DEVICE_NUM);
	
	printk("<xyd> call %s()\n",__func__);
}
 
module_init(virtdev_init);
module_exit(virtdev_exit);
MODULE_LICENSE("GPL");
